using Agron.Security.ClientLayer;
using Agron.Services.Contracts;
using Agron.Services.Proxies;

using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Security.Cryptography;
using System.Security.Principal;
using System.ServiceModel;
using System.Text;
using System.Windows.Forms;


namespace Agron.UI.SmartClient
{
    partial class LoginForm : ComponentFactory.Krypton.Toolkit.KryptonForm
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="LoginForm"/> class.
        /// </summary>
        public LoginForm()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Handles the Load event of the LoginForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void LoginForm_Load(object sender, EventArgs e)
        {
            if (Properties.Settings.Default.RememberLogin)
            {
                try
                {
                    this.usernameTextBox.Text = Decrypt(Properties.Settings.Default.SavedUsername);
                    this.passwordTextBox.Text = Decrypt(Properties.Settings.Default.SavedPassword);

                    base.Activated += delegate { this.loginKryptonButton.Focus(); };
                }
                catch (InvalidOperationException exception)
                {
                    if (ExceptionPolicy.HandleException(exception, Constants.SmartClientExceptionPolicy))
                        throw;

                    MessageBoxService.ReportError(this, exception.Message);
                }
            }
            else
            {
                base.Activated += delegate { this.usernameTextBox.Focus(); };
            }
        }

        /// <summary>
        /// Handles the Click event of the loginButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void loginButton_Click(object sender, EventArgs e)
        {
            base.Cursor = Cursors.WaitCursor;
            this.usernameTextBox.Enabled = false;
            this.passwordTextBox.Enabled = false;
            this.loginKryptonButton.Enabled = false;
            this.rememberPasswordCheckBox.Enabled = false;

            this.loginBackgroundWorker.RunWorkerAsync(new object[] { this.usernameTextBox.Text, this.passwordTextBox.Text });
        }

        /// <summary>
        /// Handles the DoWork event of the loginBackgroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
        private void loginBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            object[] args = (object[]) e.Argument;
            string username = (string) args[0];
            string password = (string) args[1];

            using (MembershipServiceProxy membershipService = new MembershipServiceProxy())
            {
                e.Result = membershipService.ValidateUser(username, password);
            }
        }

        private void loginBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            base.Cursor = Cursors.Default;
            this.loginKryptonButton.Enabled = true;
            this.usernameTextBox.Enabled = true;
            this.passwordTextBox.Enabled = true;
            this.rememberPasswordCheckBox.Enabled = true;

            if (null == e.Error)
            {
                bool isValid = (bool) e.Result;

                if (isValid)
                {
                    // Save Username and Password
                    if (this.rememberPasswordCheckBox.Checked)
                    {
                        Properties.Settings.Default.RememberLogin = true;
                        Properties.Settings.Default.SavedPassword = Encrypt(this.passwordTextBox.Text);
                        Properties.Settings.Default.SavedUsername = Encrypt(this.usernameTextBox.Text);
                        Properties.Settings.Default.Save();
                    }

                    // Initialize principal
                    AgronPrincipal.Initialize(this.usernameTextBox.Text);

                    // Display Main Form
                    MainForm mainForm = new MainForm();
                    mainForm.Show();
                    this.Hide();
                }
                else
                {
                    this.rememberPasswordCheckBox.Checked = false;
                    this.passwordTextBox.Clear();
                    this.passwordTextBox.Focus();

                    MessageBox.Show(this, Properties.Resources.LoginFormLoginFailure, Application.ProductName, MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, (MessageBoxOptions) 0);
                }
            }
            else
            {
                if (e.Error is CommunicationException)
                {
                    MessageBoxService.ReportError(this, Properties.Resources.GlobalConnectionFailed);
                }
                else
                {
                    if (!ExceptionPolicy.HandleException(e.Error, Constants.SmartClientExceptionPolicy))
                        throw e.Error;
                }
            }
        }

        private static string Decrypt(string encryptedBase64String)
        {
            if (string.IsNullOrEmpty(encryptedBase64String))
                return null;

            try
            {
                byte[] bytes = ProtectedData.Unprotect(
                    /*encryptedData*/ Convert.FromBase64String(encryptedBase64String), 
                    /*optionalEntropy*/ Encoding.Unicode.GetBytes(Constants.EncryptionEntropy), 
                    /*scope*/ DataProtectionScope.CurrentUser);

                return Encoding.Unicode.GetString(bytes);
            }
            catch (FormatException formatex)
            {
                throw new InvalidOperationException(Properties.Resources.LoginFormCryptographicFailure, formatex);
            }
            catch (CryptographicException cryptoex)
            {
                throw new InvalidOperationException(Properties.Resources.LoginFormCryptographicFailure, cryptoex);
            }
        }

        private static string Encrypt(string input)
        {
            if (string.IsNullOrEmpty(input))
                return null;

            try
            {
                byte[] encryptedData = ProtectedData.Protect(
                    /*userData*/ Encoding.Unicode.GetBytes(input),
                    /*optionalEntropy*/ Encoding.Unicode.GetBytes(Constants.EncryptionEntropy),
                    /*scope*/ DataProtectionScope.CurrentUser);

                return Convert.ToBase64String(encryptedData);
            }
            catch (FormatException formatex)
            {
                throw new InvalidOperationException(Properties.Resources.LoginFormCryptographicFailure, formatex);
            }
            catch (CryptographicException cryptoex)
            {
                throw new InvalidOperationException(Properties.Resources.LoginFormCryptographicFailure, cryptoex);
            }
        }

        /// <summary>
        /// Handles the LinkClicked event of the forgotPasswordLinkLabel control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void forgotPasswordLinkLabel_LinkClicked(object sender, EventArgs e)
        {
            string targetUrl = string.Format(CultureInfo.InvariantCulture, "{0}/Forms/RecoverPasswordForm.aspx", Properties.Settings.Default.WebsiteUrl);
            Process.Start(targetUrl);
        }

        /// <summary>
        /// Handles the KeyUp event of the passwordTextBox control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.KeyEventArgs"/> instance containing the event data.</param>
        private void passwordTextBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (Keys.Enter == e.KeyCode)
            {
                e.Handled = true;
                this.loginKryptonButton.PerformClick();
            }
        }

        /// <summary>
        /// Handles the LinkClicked event of the registerLinkLabel control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void registerLinkLabel_LinkClicked(object sender, EventArgs e)
        {
            string targetUrl = string.Format(CultureInfo.InvariantCulture, "{0}/Forms/RegisterForm.aspx", Properties.Settings.Default.WebsiteUrl);
            Process.Start(targetUrl);
        }
    }
}